package com.i2works.smartluolong.utils.plugin;


import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * mybatis通用生成工具
 * 可生成业务接口、dao接口、实体类、映射文件。
 *
 * @author Liu Yutao
 * @className mbTools
 * @email koal@vip.qq.com
 * @date 2016/3/10 19:44
 */

public class CodeMyBatisTools {
    private static final String driver = "com.mysql.jdbc.Driver";//驱动
    private static final String user = "root";  //数据库账号
    private static final String pwd = "123456"; //数据库密码
    private static final String url = "jdbc:mysql://192.168.1.100:3306/smart_fayuan_database" + "?user=" + user + "&password=" + pwd+"&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull"; //链接参数
    private static final String tableName = "court_asset"; // 数据库表名
    private static final String aliasName = "court_asset"; // 数据库别名,可以与数据库表名相同
    private static final String packageName = "请手工指定DAO接口路径"; //mapper.xml命名空间路径
    private static final String author = "lihaoyu"; // 作者
    private static final String rootPathName = "myCode/web/"; // 默认生成主文件夹路径
    private static final String batchAliasName = "ids"; //  批量删除接收参数别名
    private static Connection getConnection = null;
    static SimpleDateFormat format = new SimpleDateFormat("YYYY-HH-DD HH:mm:ss");
    /**
     * 链接数据库
     */
    private static Connection getConnections() {
        try {
            Class.forName(driver);
            getConnection = DriverManager.getConnection(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return getConnection;
    }

    /**
     * 格式化默认值
     */
    private static String defaultValue(String value) {
        if (StringUtils.isNotBlank(value)) {
            return "；默认值：" + value;
        }
        {
            return "";
        }
    }

    /**
     * 格式化数据类型
     * 返回的是基本类型的包装类
     * 如果使用基本数据类型long
     */
    private static String formatType(String typeValue) {

        if ("bit".equalsIgnoreCase(typeValue)) {
            return "Boolean";
        }
        else if (
                typeValue.equalsIgnoreCase("int") || typeValue.equalsIgnoreCase("int unsigned")
                        || typeValue.equalsIgnoreCase("tinyint") || typeValue.equalsIgnoreCase("tinyint unsigned")
                        || typeValue.equalsIgnoreCase("smallint") || typeValue.equalsIgnoreCase("smallint unsigned")
                        || typeValue.equalsIgnoreCase("mediumint") || typeValue.equalsIgnoreCase("mediumint unsigned")
                ) {
            return "Integer";
        } else if (typeValue.equalsIgnoreCase("bigint") || typeValue.equalsIgnoreCase("bigint unsigned")) {
            return "Long";
        } else if (typeValue.equalsIgnoreCase("float") || typeValue.equalsIgnoreCase("float unsigned")) {
            return "Float";
        } else if (typeValue.equalsIgnoreCase("decimal") || typeValue.equalsIgnoreCase("decimal unsigned") || typeValue.equalsIgnoreCase("numeric") || typeValue.equalsIgnoreCase("numeric unsigned")
                || typeValue.equalsIgnoreCase("real") || typeValue.equalsIgnoreCase("real unsigned") || typeValue.equalsIgnoreCase("money") || typeValue.equalsIgnoreCase("money unsigned")
                || typeValue.equalsIgnoreCase("smallmoney") || typeValue.equalsIgnoreCase("smallmoney unsigned")) {
            return "Double";
        } else if (typeValue.equalsIgnoreCase("varchar") || typeValue.equalsIgnoreCase("char")
                || typeValue.equalsIgnoreCase("nvarchar") || typeValue.equalsIgnoreCase("nchar")
                || typeValue.equalsIgnoreCase("text")) {
            return "String";
        } else if (typeValue.equalsIgnoreCase("datetime")) {
            return "Date";
        } else if (typeValue.equalsIgnoreCase("image")) {
            return "Blod";
        } else {
            return "Long";
        }

    }


    /**
     * 驼峰转换
     */
    private static String columnToProperty(String column) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (column == null || column.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!column.contains("_")) {
            // 不含下划线，仅将首字母小写
            return column.substring(0, 1).toLowerCase() + column.substring(1);
        } else {
            // 用下划线将原始字符串分割
            String[] columns = column.split("_");
            for (String columnSplit : columns) {
                // 跳过原始字符串中开头、结尾的下换线或双重下划线
                if (columnSplit.isEmpty()) {
                    continue;
                }
                // 处理真正的驼峰片段
                if (result.length() == 0) {
                    // 第一个驼峰片段，全部字母都小写
                    result.append(columnSplit.toLowerCase());
                } else {
                    // 其他的驼峰片段，首字母大写
                    result.append(columnSplit.substring(0, 1).toUpperCase()).append(columnSplit.substring(1).toLowerCase());
                }
            }
            return result.toString();
        }
    }

    /**
     * 实体名称转换
     */
    private static String formatBeanName(String column) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (column == null || column.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!column.contains("_")) {
            // 不含下划线，仅将首字母大写
            return column.substring(0, 1).toUpperCase() + column.substring(1);
        } else {
            // 用下划线将原始字符串分割
            String[] columns = column.split("_");
            for (String columnSplit : columns) {
                // 跳过原始字符串中开头、结尾的下换线或双重下划线
                if (columnSplit.isEmpty()) {
                    continue;
                }
                // 处理真正的驼峰片段
                result.append(columnSplit.substring(0, 1).toUpperCase()).append(columnSplit.substring(1).toLowerCase());
            }
            return result.toString();
        }
    }


    /**
     * 格式化方法的实参名称(首字母小写)
     *
     * @param str
     * @return
     */
    private static String formatParamName(String str) {
        return str.substring(0, 1).toLowerCase() + str.substring(1);
    }


    /**
     * 生成mybatis字段列表
     */
    private static String getColumns() {

        getConnection = getConnections();
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成查询字段 开始===================================================");
        try {
            //Thread.sleep(200);
            DatabaseMetaData dbmd = getConnection.getMetaData();
            ResultSet rs = dbmd.getColumns(null, "%", tableName, "%");
            sb.append("\n<sql id=\"" + aliasName + "_columns\">\n");
            while (rs.next()) {
                sb.append("\ta." + rs.getString("COLUMN_NAME") + " AS \"" + columnToProperty(rs.getString("COLUMN_NAME")) + "\"");
                if (!rs.isLast()) {
                    sb.append(",\n");
                } else {
                    sb.append("\n");
                }
            }
            sb.append("</sql>\n");
            //  System.out.println(sb);
            //Thread.sleep(200);
            // System.err.println("=======================================生成查询字段 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * 生成mybatis判断语句
     */
    private static String getWhere() {

        getConnection = getConnections();
        StringBuilder sb = new StringBuilder();
        //System.err.println("\n=======================================生成判断语句 开始===================================================");
        try {
            DatabaseMetaData dbmd = getConnection.getMetaData();
            ResultSet rs = dbmd.getColumns(null, "%", tableName, "%");
            sb.append("\n<sql id=\"where_" + aliasName + "_query\">\n\t<where>\n");
            while (rs.next()) {
                sb.append("\t\t<if test=\"" + columnToProperty(rs.getString("COLUMN_NAME")) + " != null\">and a." + rs.getString("COLUMN_NAME") + " = #{" + columnToProperty(rs.getString("COLUMN_NAME")) + "}</if>\n");
            }
            sb.append("\t</where>\n</sql>\n");
            //System.err.println("=======================================生成判断语句 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * 生成mybatis列表查询语句
     */
    private static String getSelectList() {
        StringBuilder sb = new StringBuilder();
        //System.err.println("\n=======================================生成列表查询 开始===================================================");
        try {
            sb.append("\n<select id=\"queryList\" parameterType=\"" + formatBeanName(aliasName) + "Query\" resultType=\"" + formatBeanName(aliasName) + "DO\">\n");
            sb.append("\tSELECT \n");
            sb.append("\t\t<include refid=\"" + aliasName + "_columns\"/>\n");
            sb.append("\tFROM \n\t" + tableName + " a \n");
            sb.append("\t\t<include refid=\"where_" + aliasName + "_query\"/>\n");
            sb.append("\tORDER BY\n");
            sb.append("\t\ta.id DESC\n");
            sb.append("\tLIMIT #{offset},#{limit}\n");
            sb.append("</select>\n");
            //System.err.println("=======================================生成列表查询 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * 生成mybatis列表统计语句
     */
    private static String getSelectCount() {
        StringBuilder sb = new StringBuilder();
        //System.err.println("\n=======================================生成列表统计 开始===================================================");
        try {
            sb.append("\n<select id=\"queryCount\" parameterType=\"" + formatBeanName(aliasName) + "Query\" resultType=\"int\">\n");
            sb.append("\tSELECT \n");
            sb.append("\t\tCOUNT(1) \n");
            sb.append("\tFROM \n\t" + tableName + " a \n");
            sb.append("\t\t<include refid=\"where_" + aliasName + "_query\"/>\n");
            sb.append("\t</select>\n");
            // System.err.println("=======================================生成列表统计 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * 生成mybatis实体查询语句
     */
    private static String getSelectOne() {
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成实体查询 开始===================================================");
        try {
            sb.append("\n<select id=\"query\" parameterType=\"" + formatBeanName(aliasName) + "Query\" resultType=\"" + formatBeanName(aliasName) + "DO\">\n");
            sb.append("\tSELECT \n");
            sb.append("\t\t<include refid=\"" + aliasName + "_columns\"/>\n");
            sb.append("\tFROM \n\t" + tableName + " a \n");
            sb.append("\t\t<include refid=\"where_" + aliasName + "_query\"/>\n");
            sb.append("\t\tLIMIT 1\n");
            sb.append("\t</select>\n");
            // System.err.println("=======================================生成实体查询 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * 生成mybatis实体新增语句
     */
    private static String getInsert() {
        getConnection = getConnections();
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成新增实体 开始===================================================");
        try {
            DatabaseMetaData dbmd = getConnection.getMetaData();
            ResultSet rs1 = dbmd.getColumns(null, "%", tableName, "%");
            ResultSet rs2 = dbmd.getColumns(null, "%", tableName, "%");
            sb.append("\n<insert id=\"save\" parameterType=\"" + formatBeanName(aliasName) + "DO\"  keyProperty=\"id\" useGeneratedKeys=\"true\">\n");
            sb.append("\tINSERT INTO " + tableName + " (\n");
            while (rs1.next()) {
                if (rs1.getString("COLUMN_NAME").equalsIgnoreCase("id") || rs1.getString("COLUMN_NAME").equalsIgnoreCase("status") || rs1.getString("COLUMN_NAME").equalsIgnoreCase("sort")) {
                    continue;
                } else if (!rs1.isLast()) {
                    sb.append("\t\t" + rs1.getString("COLUMN_NAME") + ",\n");
                } else {
                    sb.append("\t\t" + rs1.getString("COLUMN_NAME") + "\n\t)\n");
                }
            }
            sb.append("\tVALUE\n");
            sb.append("\t(\n");
            while (rs2.next()) {
                if (rs2.getString("COLUMN_NAME").equalsIgnoreCase("update_time") && rs2.isLast()) {
                    sb.append("\t\tnow()\n\t)\n");
                } else if (rs2.getString("COLUMN_NAME").equalsIgnoreCase("create_time")) {
                    sb.append("\t\tnow(),\n");
                } else if (rs2.getString("COLUMN_NAME").equalsIgnoreCase("id") || rs2.getString("COLUMN_NAME").equalsIgnoreCase("status") || rs2.getString("COLUMN_NAME").equalsIgnoreCase("sort")) {
                    continue;
                } else {
                    sb.append("\t\t#{" + columnToProperty(rs2.getString("COLUMN_NAME")) + "},\n");
                }

            }
            sb.append("\t</insert>\n");
            // System.err.println("=======================================生成新增实体 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * 生成mybatis更新语句
     */
    private static String getUpdate() {
        getConnection = getConnections();
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成新增实体 开始===================================================");
        try {
            DatabaseMetaData dbmd = getConnection.getMetaData();
            ResultSet rs = dbmd.getColumns(null, "%", tableName, "%");
            sb.append("\n<update id=\"update\" parameterType=\"" + formatBeanName(aliasName) + "DO\">\n");
            sb.append("\tUPDATE " + tableName + " SET \n");
            while (rs.next()) {
                if (rs.getString("COLUMN_NAME").equalsIgnoreCase("update_time") && rs.isLast()) {
                    sb.append("\t\tupdate_time = now()\n");
                } else if (rs.getString("COLUMN_NAME").equalsIgnoreCase("create_time")) {
                    sb.append("\t\tcreate_time = now(),\n");
                } else {
                    sb.append("\t\t<if test=\"" + columnToProperty(rs.getString("COLUMN_NAME")) + " != null\"> " + rs.getString("COLUMN_NAME") + " = #{" + columnToProperty(rs.getString("COLUMN_NAME")) + "},</if>\n");
                }
            }

            sb.append("\tWHERE\n");
            sb.append("\t\tid = #{id}\n");
            sb.append("</update>\n");
            // System.err.println("=======================================生成新增实体 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * 生成mybatis删除语句
     */
    private static String getDelete() {
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================删除语句 开始===================================================");
        try {
            sb.append("\n<delete id=\"delete\" parameterType=\"Integer\">\n");
            sb.append("\tDELETE \n");
            sb.append("\tFROM \n");
            sb.append("\t\t" + tableName + "\n");
            sb.append("\tWHERE\n");
            sb.append("\t\tid = #{value}\n");
            sb.append("\t</delete>\n");
            // System.err.println("=======================================删除语句 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * 生成mybatis批量删除
     */
    private static String getDeleteBatch() {
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================批量删除 开始===================================================");
        try {
            sb.append("\n<delete id=\"deleteBatch\">\n" +
                    "\tDELETE\n" +
                    "\tFROM\n" +
                    "\t" + tableName + "\n" +
                    "\tWHERE id IN\n" +
                    "\t\t<foreach collection=\"list\" item=\"" + batchAliasName + "\" open=\"(\" close=\")\" separator=\",\">\n" +
                    "\t\t\t#{" + batchAliasName + "}\n" +
                    "\t\t</foreach>\n" +
                    "\t</delete>\n");
            // System.err.println("=======================================批量删除 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * 生成mybatis批量更新状态
     */
    private static String getBatchStatus() {
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成实体查询 开始===================================================");
        try {
            sb.append("\n<update id=\"updateBatchStatus\" parameterType=\"java.util.Map\">\n" +
                    "\tupdate " + tableName + " set\n" +
                    "\tstatus = #{status},\n" +
                    "\tupdate_name = #{updateName},\n" +
                    "\tupdate_time = now()\n" +
                    "\twhere id IN\n" +
                    "\t<foreach collection=\"idsList\" item=\"ids\" index=\"index\" open=\"(\" close=\")\" separator=\",\">\n" +
                    "\t\t${ids}\n" +
                    "\t</foreach>\n" +
                    "\t</update>\n");
            // System.err.println("=======================================生成实体查询 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * 生成mybatis验证是否存在
     */
    private static String getCheck() {
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成实体查询 开始===================================================");
        try {
            sb.append("\n<select id=\"queryCheck\" parameterType=\"" + formatBeanName(aliasName) + "Query\" resultType=\"int\">\n" +
                    "\tSELECT\n" +
                    "\tcount(1)\n" +
                    "\tFROM\n" +
                    "\t" + tableName + " AS a\n" +
                    "\tWHERE\n" +
                    "\ta.id NOT IN(#{id})\n" +
                    "\t</select>");
            // System.err.println("=======================================生成实体查询 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }
    
    
    /**
     * 实体类字段
     */
    private static void getBean() {

        getConnection = getConnections();
        StringBuilder sb = new StringBuilder();
        //System.err.println("\n=======================================生成实体属性 开始===================================================");
        try {
        	String beanName = formatBeanName(aliasName);
            DatabaseMetaData dbmd = getConnection.getMetaData();
            ResultSet rs = dbmd.getColumns(null, "%", tableName, "%");
            sb.append(  " /**\n" +
	                    "  *\n" +
	                    "  * @author " + author + "\n" +
	                    "  * @date "+ format.format(new Date())+"\n" +
	                    "  */\n" +
	                    "public class "+beanName+"DO  extends BaseCommDO{\n");
            while (rs.next()) {
                sb.append("\tprivate ").append(formatType(rs.getString("TYPE_NAME"))).append(" ").append(columnToProperty(rs.getString("COLUMN_NAME"))).append("; // ").append(rs.getString("REMARKS")).append(defaultValue(rs.getString("COLUMN_DEF"))).append("\n");
            }
            sb.append("   } ");
            //System.err.println("=======================================生成实体属性 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        write(sb.toString(),"DO.java");
        System.err.println("\n类型：JAVA数据层实体类（bean.java）" + "\n状态：成功" + "\n时间：" + format.format(new Date()) + "\n");
    }
    

    /**
     * 生成DAO层接口
     */
    private static void getDao() {
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成dao 开始===================================================");
        try {
            String beanName = formatBeanName(aliasName);
            sb.append(  "/**\n" +
	                    " *\n" +
	                    " * @author " + author + "\n" +
	                    " * @date "+ format.format(new Date())+"\n" +
	                    " */\n" +
	                    "@Mapper \n" +
	                    "@Repository(\""+formatParamName(beanName)+"DAO\")\n" +
	                    "public interface I"+beanName+"DAO extends BaseCommonDAO<"+beanName+"Query, "+beanName+"DO>{\n" +
	                    " \n" +
	            		"}");
            // System.err.println("=======================================生成dao 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        write(sb.toString(),"DAO.java");
        System.err.println("\n类型：JAVA数据持久层接口（dao.java）" + "\n状态：成功" + "\n时间：" + format.format(new Date()) + "\n");
    }

    
    /**
     * 生成SERVICE层接口
     */
    private static void getService() {
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成service 开始===================================================");
        try {
            String beanName = formatBeanName(aliasName);
            sb.append(  "/**\n" +
	                    " *\n" +
	                    " * @author " + author + "\n" +
	                    " * @date "+ format.format(new Date())+"\n" +
	                    " */\n" +
	                    "public interface I"+beanName+"Service extends BaseCommonService<"+beanName+"Query, "+beanName+"DO>{\n" +
	                    "\n" +
	            		"}");
            // System.err.println("=======================================生成service 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        write(sb.toString(),"Service.java");
        System.err.println("\n类型：JAVA业务层接口（service.java）" + "\n状态：成功" + "\n时间：" + format.format(new Date()) + "\n");
       
    }

    
    /**
     * 生成SERVICE层实现类
     */
    private static void getServiceImpl() {
        StringBuilder sb = new StringBuilder();
        // System.err.println("\n=======================================生成serviceImpl 开始===================================================");
        try {
            String beanName = formatBeanName(aliasName);
            sb.append(  "/**\n" +
	                    " *\n" +
	                    " * @author " + author + "\n" +
	                    " * @date "+ format.format(new Date())+"\n" +
	                    " */\n" +
	                    "@Service(\""+formatParamName(beanName)+"Service\")\n" +
	                    "public class "+beanName+"ServiceImpl extends BaseCommonServiceImpl<"+beanName+"Query, "+beanName+"DO>implements I"+beanName+"Service{\n" +
	                    " \n" +
	            		"} ");
         // System.err.println("=======================================生成serviceImpl 结束===================================================");
        } catch (Exception e) {
            e.printStackTrace();
        }
        write(sb.toString(),"ServiceImpl.java");
        System.err.println("\n类型：JAVA业务层实现类（serviceImpl.java）" + "\n状态：成功" + "\n时间：" + format.format(new Date()) + "\n");
        
    }

    /**
     * 生成mapper.xml
     */
    private static void getMapperXML() {
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
                "<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n" +
                "<mapper namespace=\"" + packageName + ".I" + formatBeanName(aliasName) + "DAO\">");
        sb.append(getColumns() +
                getWhere() +
                getSelectList() +
                getSelectCount() +
                getSelectOne() +
                getInsert() +
                getUpdate() +
                getBatchStatus() +
                getDelete() +
                getDeleteBatch() +
                getCheck()
        );
        sb.append("\n</mapper>\n");
        write(sb.toString(),"Mapper.xml");
        System.err.println("\n类型：MyBatis映射文件（Mapper.xml）" + "\n状态：成功" + "\n时间：" + format.format(new Date()) + "\n");
        
    }


    /**
     * 写文件，支持中文字符，在linux redhad下测试过
     * @param str 文本内容
     * @param name 文本名称
     * */
    private static void write(String str, String name) {
        try {
            File dir = new File(rootPathName + "/" + formatBeanName(aliasName));
            dir.mkdirs();
            String path = dir.getPath() + "/" + formatBeanName(aliasName)+name;
            if(name.equals("DAO.java")||name.equals("Service.java")) {
             path = dir.getPath() + "/I" + formatBeanName(aliasName)+name;	
            }
            File file = new File(path);
            if (!file.exists())
                file.createNewFile();
            FileOutputStream out = new FileOutputStream(file, false); //如果追加方式用true
            StringBuilder sb = new StringBuilder();
            sb.append(str + "\n");
            out.write(sb.toString().getBytes("utf-8"));//注意需要转换对应的字符集
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




 
    public static void main(String[] args) {
        //实体
    	getBean();
    	//dao层接口
    	getDao();
        //业务类接口
    	getService();
    	//业务类实现类
    	getServiceImpl();
        //mapper.xml文件
    	getMapperXML();
    }

}
